package com.wxsm.wechat.core.exception;

import com.wxsm.wechat.core.exception.ExceptionEnum;
import com.wxsm.wechat.model.CommonJsonResult;
import com.wxsm.wechat.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

import static com.wxsm.wechat.model.CommonJsonResult.fail;

/**
 * 异常处理
 * Created with Yang Huan
 * Date: 2017/3/2
 * Time: 11:34
 */
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class);

    /**
     * 服务端异常处理
     *
     * @param ex
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    protected ResponseEntity<Object> serverExceptionHandler(Exception ex) throws Exception {
        logger.error("Catch server Exception:", ex);
        CommonJsonResult commonJsonResult;
        if (ex instanceof ServiceException) {
            commonJsonResult = fail(ExceptionEnum.valueOfRestException((ServiceException) ex));
        } else if (ex instanceof ConstraintViolationException) {
            List<String> messages = new ArrayList<>();
            for (ConstraintViolation constraintViolation : ((ConstraintViolationException) ex).getConstraintViolations()) {
                messages.add(constraintViolation.getMessage());
            }
            commonJsonResult = fail(ExceptionEnum.REQUEST_DATA_ERROR.replaceValue(JsonUtil.toJson(messages)));
        } else if (ex instanceof DataAccessException) {
            commonJsonResult = fail(ExceptionEnum.SQL_EXECUTE_ERROR);
        } else if (ex instanceof IllegalArgumentException) {
            commonJsonResult = fail(ExceptionEnum.REQUEST_DATA_ERROR.replaceValue(ex.getMessage()));
        } else {
            commonJsonResult = fail(ExceptionEnum.SYS_ERROR);
        }
        return new ResponseEntity<>(commonJsonResult, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 客服端异常处理
     *
     * @param ex
     * @param body
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        logger.error("Catch internal Exception:", ex);
        CommonJsonResult commonJsonResult;
        if (ex instanceof BindException) {
            String message = ((BindException) ex).getFieldErrors().get(0).getDefaultMessage();
            commonJsonResult = fail(ExceptionEnum.REQUEST_DATA_ERROR.replaceValue(message));
        } else if (ex instanceof MethodArgumentNotValidException) {
            String message = ((MethodArgumentNotValidException) ex).getBindingResult().getFieldErrors().get(0).getDefaultMessage();
            commonJsonResult = fail(ExceptionEnum.REQUEST_DATA_ERROR.replaceValue(message));
        } else if (ex instanceof MethodArgumentTypeMismatchException) {
            commonJsonResult = fail(ExceptionEnum.REQUEST_DATA_ERROR.replaceValue("参数类型不匹配"));
        } else {
            commonJsonResult = fail(ExceptionEnum.SYS_ERROR.replaceValue("客户端异常, 请刷新重试"));
        }
        return new ResponseEntity<>(commonJsonResult, headers, HttpStatus.BAD_REQUEST);
    }
}
